extends Node3D

@onready var node_konservejo = Title.get_node("CanvasLayer/UI/konservejo/konservejo")

var uuid #нужно для идентификации конкретного модуля
var objekto
var integreco # целостность объекта
var potenco # мощность ресурса

@export (float) var beam_length = 1000
@export (float) var speed_rotation = 3
@export (Color, RGBA) var laser_color :Color = Color(1.0,0.0,0.0,1.0)
@export var x_limiter: Vector2=Vector2(0.0,90.0)
@export var y_limiter: Vector2=Vector2(-90.0,90.0)
var new_target = null # задание новой цели
#если таргет сняли или поменяли до окончания показа выстрела, то выстрел демонстрируем до конца по старой цели
var target = null # ведём цель и стреляем
var livero = 0 # произошел выстрел на 1 перезарядка
var id_livero = [] # id ответов по произведённым выстрелам, уменьшаем кол-во боезапаса

var id_test

var tuttempe_pafo = 50 # в течении времени показывать выстрел
var malfruo = 100 # время задержки выстрела/перезарядка
var kvanto_pafajho = -1 # количество снарядов Если -1 то бесконечный боезапас
#сам лазер отправляет на сервер что он выстрелил и по кому
# обрабатывает результат выстрела оружие - уменьшая кол-во боеприпасов у себя в заряде

var sxipo # указатель на корабль, где установлено данное оружие. Нужно для ведения огня


func _ready():
#	target=get_parent().route #это потом удалить, здесь тестовое получение цели.
	$laser.target_position.z = -beam_length #устанавливаем максимальную дальность лазера.
	$laser/beam/MeshInstance3D.mesh.material.set("shader_param/laser_color",laser_color)
	$laser/beam/MeshInstance2.mesh.material.set("shader_param/laser_color",laser_color)

	# подключаем сигнал для обработки входящих данных
	var err = Net.connect("input_data", Callable(self, "_on_data"))
	if err:
		print('error = ',err)


func _on_data():
	var i_data_server = 0
	var masivo_forigo = [] # массив индексов на удаление
	for on_data in Net.data_server:
		var index = id_livero.find(int(on_data['id']))
		if index > -1: # находится в списке выстрелов
#			уменьшаем количество снарядов в оружии
			if kvanto_pafajho>0:
				kvanto_pafajho -= 1
			pass
			id_livero.remove(index)
			masivo_forigo.insert(0, i_data_server) # удаляем после окончания цикла
		elif id_test == int(on_data['id']):
			print('===id_test==',on_data)
			id_test = 0
			masivo_forigo.insert(0, i_data_server) # удаляем после окончания цикла
		i_data_server += 1
	for forigo in masivo_forigo:
		Net.data_server.remove(forigo)


#func _input(event):
	# обработаем реакцию наведения лазера
#	get_tree().set_input_as_handled() #для предотвращения повторного ответа других узлов

#Input.is_key_pressed(scancode)
#@Global Scope 

#при этом устанавливаем всем остальным кораблям:
#	set_process_input(enable) # Установите enable to false для остановки получения обратного вызова. Установите его в true
# повторно подпишет узел для получения входных событий. 



func rotate_gun(delta):
#	поворачивает мимо цели дальше
#	var temp = transform.basis #сохраняем старый базис
#	look_at(target.get_global_transform().origin,Vector3.UP)#смотрим на цель, это сохранится в текущем базисе, из-за этого и куча движений с буферными базисами
#	print('смотрим = ',get_uuid($laser.get_collider()))
#	var target_rot = transform.basis#сохраняем целевой базис
#	transform.basis = temp#восстанавливаем изначальный базис
#	$laser.transform.basis = $laser.transform.basis.slerp(target_rot,speed_rotation*delta) # постепенно поворачиваем к цели
	if sercxado_uuid(target.uuid,$laser.get_collider()):
		return
	var temp = $laser.transform.basis #сохраняем старый базис
	$laser.look_at(target.get_global_transform().origin,Vector3.UP)#смотрим на цель, это сохранится в текущем базисе, из-за этого и куча движений с буферными базисами
#	print('смотрим = ',get_uuid($laser.get_collider()))
	var target_rot = $laser.transform.basis#сохраняем целевой базис
	$laser.transform.basis = temp#восстанавливаем изначальный базис
	$laser.transform.basis = $laser.transform.basis.slerp(target_rot,speed_rotation*delta) # постепенно поворачиваем к цели
	
	
	
	
	$laser.rotation_degrees.x = clamp($laser.rotation_degrees.x,x_limiter.x,x_limiter.y)# ограничиваем вращение пушки вниз, чтобы стреляла только в верхнюю полусферу
	$laser.rotation_degrees.y = clamp($laser.rotation_degrees.y,y_limiter.x,y_limiter.y)# ограничиваем вращение пушки по сторонам, если нужно
	$gun_body.rotation.y = $laser.rotation.y
	$Turret.rotation.y = $laser.rotation.y


func get_uuid(objekt):
	if not objekt:
		return 'space 0'
	if objekt.get('uuid'):
		return objekt.uuid
	else:
		if objekt.get_parent().name != 'space':
			return get_uuid(objekt.get_parent())
		else:
			return 'space'


# проверка, входит ли uuid в данный объект
#	я могу видеть часть от целого, нужно подняться к предку и проверить его uuid
# проверяем по восходящей до космоса
func sercxado_uuid(parametro_uuid, objekt):
	if not objekt:
		return false
	if objekt.get('uuid'):
		if parametro_uuid == objekt.uuid:
			return true
	if objekt.get_parent().name != 'space':
		return sercxado_uuid(parametro_uuid, objekt.get_parent())
	return false


func _physics_process(delta):
	if target:
		var length_to_end=beam_length
		var can_shoot = false
		rotate_gun(delta)
		if $laser.is_colliding():
			if sercxado_uuid(target.uuid,$laser.get_collider()):
	#			print($laser.get_collider().name) #тут можно обработать в кого мы попали и вызвать повреждения.
				length_to_end = get_global_transform().origin.distance_to($laser.get_collision_point())
#				print('тут 1 kvanto_pafajho=',kvanto_pafajho,' tuttempe_pafo=',tuttempe_pafo,' livero=',livero)
				if (tuttempe_pafo>livero) and ((kvanto_pafajho==-1)or(kvanto_pafajho>0)):
					can_shoot = true
					$laser/end_point.visible = true
					$laser/beam.visible = true
					if !livero: # только начали стрелять
						livero = 1 # начало стрельбы после всех проверок
				else:
					$laser/end_point.visible = false
					$laser/beam.visible = false
			else:
				$laser/end_point.visible = false
				$laser/beam.visible = false
		else:
			$laser/end_point.visible = false
			$laser/beam.visible = false
		
		if can_shoot:
			$laser/beam.scale.z=length_to_end
			$laser/end_point.position.z = -length_to_end
			$laser/end_point/Particles.emitting = true
		else:
			$laser/end_point/Particles.emitting = false
			$laser/beam.scale.z=0.1
			$laser/end_point.position.z = 0
	else: 
		$laser/end_point.visible = false
		$laser/beam.visible = false
	if livero > 1:
		livero += 1
	if livero == 1: # отправляем выстрел на сервер
#		#Это должно быть только на управляемом корабле, а не на оружии всех
#		if (sxipo)and(sxipo == Global.fenestro_kosmo.get_node('ship')):
#			Global.fenestro_kosmo.get_node('ui_armilo').pafo_server(self, target)
		# сервер отвечает за повреждения объектов
#		 отправляем на сервер повреждение от выстрела
		if Global.server:
			integreco_shanghi(potenco)
		livero = 2
	if livero == 10: # производим разрушение объекта цели
		pass
	if livero > malfruo:
		livero = 0
		if target != new_target:
			target = new_target # меняем цель, если за время выстрели цель поменяли или сняли


const QueryObject = preload("queries.gd")


# objekto - объект, в котором идёт поиск склада
# tipo_modulo - тип объекта поиска (склада)
func sercxo(parametro_objekto, tipo_modulo):
	for konservejo in parametro_objekto.get_children():
		if (("objekto" in konservejo) and
				konservejo.objekto['resurso']['objId']==tipo_modulo): # грузовой модуль
			return konservejo # указатель на грузовой модуль корабля
	return null


# отправляем на сервер повреждение от выстрела
func integreco_shanghi(nombro):
	if !nombro:
		print('не указана мощность выстрела')
		return
	if Global.server:
		var q = QueryObject.new()
		var id = Net.get_current_query_id()
		Net.net_id_clear.append(id)
		if Global.logs:
			print('отправляем на сервер повреждение от выстрела')
		# проверяем, если стреляем не майнинговым лазером
		if objekto['resurso']['objId']!=11:
			Net.send_json(q.integreco_shanghi(
				target.uuid,
				-nombro,
				0, 0, 0,
				id
			))
			return
		# если не астероид
		if not((target.objekto['resurso']['objId']==7) or\
				((target.objekto['resurso']['objId']>=20)and\
				(target.objekto['resurso']['objId']<=28))): # не простой астероид
			if Global.logs:
				print('это не астероид')
			Net.send_json(q.integreco_shanghi(
				target.uuid,
				-nombro/2,
				0, 0, 0,
				id
			))
			return
		# если астероид
		# если есть руда в астероиде
		if Global.logs:
			Global.saveFileLogs("=== target.objekto = ")
			Global.saveFileLogs(target.objekto)
		# находим склад
		var konservejo = sercxo(sxipo, 5)
		if !konservejo:
			if Global.logs:
				print('упс, склад не нашли :-(')
			return
		# проверяем на возможности (свойства) места, куда складывать добываемый ресурс
		# есть ли склад, куда можно положить руды с астероида
		if node_konservejo.interkonveneco_objekto(konservejo.objekto,target.objekto) == 0:
			return # нельзя поместить
		
		# хватит-ли места на все руды на складе корабля?
		# вычисляем сколько можем добыть руды от выстрела
		var volumeno = nombro / (target.objekto['integreco'] / target.objekto['volumenoEkstera'])
		# коэффициент потерь от лазера
		var koef_weapon = 1.0
		# добавить зависимость от типа добывающего лазера
		koef_weapon /= 2.0
		# коэффициент потерь от добывающего дрона
		var koef_dronej = 0.5
		# итого добыча от выстрела
		volumeno *= koef_dronej * koef_weapon
		# проверяем, хватит-ли места на все руды на складе корабля
		if Global.logs:
			Global.saveFileLogs("=== konservejo.objekto = ")
			Global.saveFileLogs(konservejo.objekto)
#		у нас несколько складов - выбираем нужный
		# на 10.02.2021 года только один склад и берём первый
#		нужно дозапросить склад у вновь появившегося корабля в космосе??
		var konservo = konservejo.objekto['stokejo'].front()
		# суммируем все объекты, лежащие в складе
		
		var volumeno_stokado = 0
		for kolvo in konservo['objekto']['edges']:
			volumeno_stokado += kolvo['node']['volumenoStokado']
		
		# свободное пространство в складе
		var volumeno_blanko = konservejo.objekto['volumenoInterna'] \
			- volumeno_stokado
		if volumeno_blanko <= 0:
			# свободного места на складе нет - выходим
			if Global.logs:
				print('свободного места на складе нет - выходим = ',volumeno_blanko)
			return
		# коэффициент потерь при складировании
		# случайное число от 0,15 до 0,25
		var koef_stokado = 1 + randf_range(0.15, 0.25)
		
		var koeficiento_volumeno = 1 # коэффициент уменьшения добытого ресурса согласно места на складе с учётом потерь хранения
		if volumeno_blanko < (volumeno*koef_stokado): # если на складе места меньше, чем мы можем добыть согласно мощности выстрела
			# нужно уменьшить добычу всех руд на % разницы
			koeficiento_volumeno = volumeno_blanko / (volumeno*koef_stokado)
		# сколько можем добыть согласно наличия руды в минерале, мощности добычи и места на борту
		var volumeno_max = 0
		if target.objekto['volumenoEkstera'] < volumeno*koeficiento_volumeno: # если руды меньше, чем мы можем добыть и взять на борт
			volumeno_max = target.objekto['volumenoEkstera']
		else:
			volumeno_max = volumeno*koeficiento_volumeno
		# объёма астероида
		var volumenoAstEkstera = target.objekto['volumenoEkstera']
		var volumenoAstInterna = target.objekto['volumenoInterna']
		var volumenoAstStokado = target.objekto['volumenoStokado']
		# enteno - содержа́ние (одной субстанции в другой)
		for enteno in target.objekto['stokejo'].front()['objekto']['edges']: # проходим по всем элементам склада
			# вычисляем сколько добыли руд
				 # находится внутри
			if (enteno['node']['volumenoEkstera']>0): # и есть руда
				# количество добытого минерала
				var volumeno_resurso_ekstera = (enteno['node']['volumenoEkstera'] / target.objekto['volumenoEkstera']) * volumeno_max
				var volumeno_resurso_intera = (enteno['node']['volumenoInterna'] / enteno['node']['volumenoEkstera']) * volumeno_resurso_ekstera
				var volumeno_resurso_stokado = (enteno['node']['volumenoStokado'] / enteno['node']['volumenoEkstera']) * volumeno_resurso_ekstera
				volumenoAstEkstera -= volumeno_resurso_ekstera
				volumenoAstInterna -= volumeno_resurso_intera
				volumenoAstStokado -= (enteno['node']['volumenoStokado'] / target.objekto['volumenoStokado']) * volumeno_max
				# если ресурсов больше, чем места в трюме
#				if enteno['node']['ligilo']['volumenoEkstera'] >= volumeno*koeficiento_volumeno:
#					volumeno_resurso = volumeno*koeficiento_volumeno
#				else:
#					volumeno_resurso = enteno['node']['ligilo']['volumenoEkstera']
				# убавляем минерала астероиду
				var volumenoEkstera = enteno['node']['volumenoEkstera'] - volumeno_resurso_ekstera
				var volumenoInterna = enteno['node']['volumenoInterna'] - volumeno_resurso_intera
				var volumenoStokado = enteno['node']['volumenoStokado'] - volumeno_resurso_stokado
				Net.send_json(q.volumeno_shanghi(
					enteno['node']['uuid'],
					volumenoInterna, 
					volumenoEkstera, 
					volumenoStokado
				))
				# увеличиваем объем хранения в нашем корабле на коэффициент складского хранение
				volumeno_resurso_stokado = volumeno_resurso_stokado * koef_stokado
				# прибавляем ресурс на склад своего корабля
				var posedantoId = Global.id
				if Global.fenestro_kosmo.get_node('ship') != sxipo:
					posedantoId = sxipo.objekto['posedantoId']
				# проверяем, есть ли на складе такой ресурс
				var uuid_resurso=""
				var resurso = null
				for kolvo in konservejo.objekto['stokejo'].front()['objekto']['edges']:
					if (kolvo['node']['resurso']['objId']==enteno['node']['resurso']['objId']): # Находится внутри и одинаковый ресурс
						uuid_resurso = kolvo['node']['uuid']
						# увеличиваем объекм ресурса на количество находящегося на складе
						volumeno_resurso_intera += kolvo['node']['volumenoInterna']
						volumeno_resurso_ekstera += kolvo['node']['volumenoEkstera']
						volumeno_resurso_stokado += kolvo['node']['volumenoStokado']
						resurso = kolvo
				if uuid_resurso: # ресурс найден
					Net.send_json(q.volumeno_shanghi(
						uuid_resurso,
						volumeno_resurso_intera, 
						volumeno_resurso_ekstera, 
						volumeno_resurso_stokado
					))
					# добавляем на склад ресурс
					resurso['node']['volumenoInterna'] = volumeno_resurso_intera
					resurso['node']['volumenoEkstera'] = volumeno_resurso_ekstera
					resurso['node']['volumenoStokado'] = volumeno_resurso_stokado
				else: # такого ресурса нет на корабле
					#место хранения, куда положить - ligiloPosedantoStokejoUuid - konservejo.objekto['stokejo'].front()['uuid']
					id_test = Net.get_current_query_id()
					Net.send_json(q.krei_objekto(
						enteno['node']['nomo']['enhavo'], 
						'',
						1, #posedantoTipoId
						1, # posedantoStatusoId
						posedantoId,  #posedantoUzantoSiriusoUzantoId,
						3, #ligiloTipoId, - находится внутри
						konservejo.objekto['uuid'], # ligiloPosedantoUuid
						enteno['node']['resurso']['objId'], # resursoId
						volumeno_resurso_intera, #volumenoInterna
						volumeno_resurso_ekstera, # volumenoEkstera
						volumeno_resurso_stokado, #volumenoStokado
						enteno['node']['stato']['posedanto']['uuid'], #modifoUuid
						enteno['node']['stato']['uuid'], #statoUuid
						konservejo.objekto['stokejo'].front()['uuid'],#ligiloPosedantoStokejoUuid
						id_test
					))
					# добавление на склад корабля ресурса произойдёт по подписке
		# уменьшаем астероиду объёмы
		Net.send_json(q.integreco_shanghi(
			target.uuid,
			-nombro,
			volumenoAstEkstera,
			volumenoAstInterna,
			volumenoAstStokado,
			id
		))

func set_target(targeto):
	if target: # при отмене стрельбы или смена цели
		new_target = targeto
	else: # сюда попадаем только при начале первой стрельбы 
		new_target = targeto
		target = targeto


